// 导入参数验证中间件
const { body, param, query, validationResult } = require('express-validator');
// 将需要验证的参数保存为对象，以便重用。
const validators = {
	mUsername: body('username').trim().isLength({ min: 3, max: 16 }).withMessage('用户名长度必须在3到16个之间'),
	qUsername: query('username').optional().trim(),
	oldUsername: body('oldUsername').trim().isLength({ min: 3, max: 16 }).withMessage('用户名长度必须在3到16个之间'),
	newUsername: body('newUsername')
		.notEmpty()
		.withMessage('新用户名不能为空')
		.trim()
		.isLength({ min: 3, max: 16 })
		.withMessage('用户名长度必须在3到16个之间'),
	password: body('password').trim().isLength({ min: 6, max: 20 }).withMessage('密码长度在6到20个之间'),
	confirmPassword: body('confirmPassword')
		.trim()
		.isLength({ min: 6, max: 20 })
		.withMessage('确认密码长度在6到20个之间')
		.custom((val, { req }) => {
			if (val != req.body.password) throw new Error('两次密码输入必须一致');
			return true;
		}),
	oldPassword: body('oldPassword').trim().isLength({ min: 6, max: 20 }).withMessage('密码长度在6到20个之间'),
	newPassword: body('newPassword').trim().isLength({ min: 6, max: 20 }).withMessage('密码长度在6到20个之间'),
	againPassword: body('againPassword')
		.trim()
		.isLength({ min: 6, max: 20 })
		.withMessage('密码长度在6到20个之间')
		.custom((val, { req }) => {
			if (val != req.body.newPassword) throw new Error('两次密码输入必须一致');
			return true;
		}),
	nickname: body('nickname')
		.notEmpty()
		.withMessage('昵称不能为空')
		.isLength({ max: 50 })
		.withMessage('昵称不能超过50个字符'),
	role: body('role').isIn(['super', 'admin', 'guest']).withMessage('管理员类型错误'),
	job: body('job').isLength({ max: 45 }).withMessage('职位名称不能超过45个字符'),
	level: body('level').isIn(['low', 'medium', 'high']).withMessage('职位等级只包含low、medium、high'),
	email: body('email').isLength({ max: 45 }).withMessage('电子邮箱长度不能超过45个字符'),
	phone: body('phone').isLength({ max: 15 }).withMessage('电话号码长度不能超过15个字符'),
	qq: body('qq').isLength({ max: 15 }).withMessage('QQ号码长度不能超过15个字符'),
	wechat: body('wechat').isLength({ max: 45 }).withMessage('微信号码长度不能超过45个字符'),
	tid: param('tid').notEmpty().toInt(),
	qTagName: query('tagName').optional().trim(),
	tagName: body('tagName')
		.notEmpty()
		.withMessage('标签不能为空')
		.trim()
		.isLength({ max: 20 })
		.withMessage('标签长度不能超过20个字符'),

	// 供应商 start
	vendor_name: body('name').trim().isLength({ max: 50 }).withMessage('供应商名长度不能超过20个字符'),
	vendor_type: body('type').isIn(['material', 'goods', 'machine']).withMessage('供应商类型错误'),
	vendor_phone: body('phone').trim().isLength({ max: 20 }).withMessage('供应商号码长度不能超过20个字符'),
	// 供应商 end

	// 项目
	project_title: body('title')
		.trim()
		.notEmpty()
		.withMessage('项目标题不能为空')
		.isLength({ max: 30 })
		.withMessage('项目标题长度不能超过30个字符'),
	project_num: body('project_num')
		.trim()
		.notEmpty()
		.withMessage('项目编号不能为空')
		.isLength({ max: 30 })
		.withMessage('项目编号长度不能超过30个字符'),
	project_priority: body('priority').isIn(['low', 'medium', 'high']).withMessage('项目重要性类型错误'),
	completion_at: body('completion_at')
		.notEmpty()
		.withMessage('项目预计完成日期不能为空')
		.isISO8601()
		.toDate()
		.withMessage('类型错误，应为时间类型'),
	total_matter: body('total_matter').optional().isInt().withMessage('类型为整型'),
	finished_matter: body('finished_matter').optional().isInt().withMessage('类型为整型'),
	editProjectsType: body('type').isIn(['is_finished', 'is_delete', '']).withMessage('状态修改字段错误'),
	// 项目人员
	manager_list: body('manager_list').custom((val) => {
		// 判断val是不是数组类型，如果是数组类型，判断数组长度和去重后的数组长度是否相等
		if (!Array.isArray(val)) {
			if (val) val = JSON.parse(val);
		}
		if (val.length !== new Set(val).size) throw new Error('项目人员重复');
		return true;
	}),
	// 事件
	matter_title: body('title')
		.trim()
		.notEmpty()
		.withMessage('事件标题不能为空')
		.isLength({ max: 30 })
		.withMessage('事件标题长度不能超过30个字符'),
	matter_description: body('description')
		.trim()
		.notEmpty()
		.withMessage('事件描述不能为空')
		.isLength({ max: 255 })
		.withMessage('事件描述不应该超过255个字符'),
	matter_type: body('type').isIn(['log', 'todo', 'inprogress', 'done']).withMessage('事件类型错误'),
	matter_tagList: body('tag_list')
		.optional()
		.custom((val) => {
			if (val) val = JSON.parse(val);
			if (!Array.isArray(val)) {
				throw new Error('事件标签类型错误');
			}

			const map = new Map([
				['id', { notEmpty: false }],
				['tag_name', { msg: '标签格式错误', require: true, isLength: { max: 20 }, notEmpty: true }],
				['color', { msg: '颜色格式错误', isLength: { max: 7 }, notEmpty: false }],
				['text_color', { msg: '文字颜色格式错误', isLength: { max: 7 }, notEmpty: false }]
			]);

			for (let i = 0; i < val.length; i++) {
				// 判断val[i]是不是对象类型，不使用typeof val[i] === 'object'是因为null也是对象类型
				if (Object.prototype.toString.call(val[i]) !== '[object Object]') throw new Error('标签类型应为数组对象');
				for (let key in val[i]) {
					if (map.has(key)) {
						const field = map.get(key);

						if (field.require && !val[i][key]) {
							throw new Error(field.msg);
						}

						if (field.notEmpty && !val[i][key]) {
							throw new Error(field.msg);
						}

						if (field.isLength && val[i][key].toString().length > field.isLength.max) {
							throw new Error(field.msg);
						}
					} else {
						throw new Error('未知字段');
					}
				}
			}

			return true;
		}),
	// 商品
	productName: body('product_name')
		.trim()
		.notEmpty()
		.withMessage('商品名不能为空')
		.isLength({ max: 50 })
		.withMessage('商品名长度不能超过50个字符'),

	// 商品-品牌 start ok
	brandId: body('brand_id').notEmpty().withMessage('商品品牌id不能为空').toInt(),
	qbrand_name: query('brand_name').optional().trim(),
	brand_name: body('brand_name')
		.notEmpty()
		.withMessage('品牌名不能为空')
		.trim()
		.isLength({ max: 20 })
		.withMessage('品牌名不能超过20个字符'),
	brand_description: body('description')
		.optional()
		.isLength({ max: 255 })
		.withMessage('品牌描述不应该超过255个字符')
		.trim()
		.escape(),
	brand_website: body('website')
		.optional()
		.isLength({ max: 255 })
		.withMessage('网址不应该超过255个字符')
		.trim()
		.escape(),
	brand_country: body('country').optional().isLength({ max: 20 }).withMessage('国家不应该超过20个字符').trim().escape(),
	brand_founded_year: body('founded_year').optional().isInt().withMessage('成立年份类型为整型'),
	editBrandField: query('field').isIn(['is_delete', 'status']).withMessage('品牌状态修改字段错误'),
	editBrandType: query('type').isIn([0, 1]).withMessage('品牌状态修改状态错误'),
	idList: query('id_list').custom((val) => {
		if (!Array.isArray(val)) {
			if (val) val = JSON.parse(val);
			if (!val || !val.length) throw new Error('品牌id不能为空');
		}
		if (val.length !== new Set(val).size) throw new Error('品牌id重复');
		return true;
	}),
	// 商品-品牌 end

	// 商品-分类 start
	category_name: body('name')
		.notEmpty()
		.withMessage('分类名不能为空')
		.trim()
		.isLength({ max: 20 })
		.withMessage('分类名长度不能超过20个字符'),
	category_ifParent: body('if_parent').optional().isIn([0, 1]).withMessage('是否为父级分类错误'),
	category_parentId: body('parent_id')
		.optional()
		.custom((val, { req }) => {
			// 如果if_parent为1，parent_id必须为空或者0
			if (req.body.if_parent === 1) {
				if (val !== 0 && val !== null) {
					throw new Error('父级分类无父分类id');
				}
			}
			return true;
		})
		.toInt(),
	category_sort: body('sort').optional().isInt().withMessage('排序类型为整型'),
	// 商品-分类 end
	editTinyintType: query('type').isIn([0, 1]).withMessage('状态错误，只为0/1'),
	categoryId: body('category_id').notEmpty().withMessage('商品标签id不能为空').toInt(),
	vendorId: body('vendor_id').notEmpty().withMessage('商品供应商id不能为空').toInt(),
	putProductName: body('product_name')
		.optional()
		.trim()
		.isLength({ max: 50 })
		.withMessage('商品名长度不能超过50个字符'),
	putBrandId: body('brand_id').optional().isInt().withMessage('品牌id类型为整型'),
	putCategoryId: body('category_id').optional().isInt().withMessage('标签id类型类型为整型'),
	putVendorId: body('vendor_id').optional().isInt().withMessage('供应商id类型为整型'),
	qSort: query(['collect_num', 'buy_num']).isIn(['desc', 'asc', '']).withMessage('排序类型错误，desc/asc'),
	// 分页
	limit: query('limit').optional().isInt().withMessage('分页限制类型为整型'),
	offset: query('offset').optional().isInt().withMessage('分页跳过类型为整型'),

	// sku start
	goodId: body('good_id').notEmpty().withMessage('商品id不能为空').toInt(),
	skuName: body('sku_name')
		.notEmpty()
		.withMessage('sku名称不能为空')
		.trim()
		.isLength({ max: 50 })
		.withMessage('sku名称长度不能超过50个字符'),
	price: body('price')
		.toFloat()
		.isFloat()
		.withMessage('单价价格为浮点数')
		.isLength({ max: 10 })
		.withMessage('单价价格最长为9个字符'),
	rebated: body('rebated')
		.toFloat()
		.isFloat()
		.withMessage('折扣价为浮点数')
		.isLength({ max: 10 })
		.withMessage('折扣价最长为9个字符'),
	stock: body('stock')
		.toInt()
		.isInt()
		.withMessage('库存为整型')
		.isLength({ max: 11 })
		.withMessage('库存最长为11个字符'),
	// sku end

  // stock start
	handlerBy: query('handler_by').optional().isInt().withMessage('经手人类型为整型'),
  skuId_o:query('sku_id').optional().toInt(),
	quantity: body('quantity')
		.toInt()
		.isInt()
		.withMessage('入库数量为整型')
		.isLength({ max: 6 })
		.withMessage('库存最长为6个字符'),
	dateOn: body('date_on')
		.notEmpty()
		.withMessage('入库日期不能为空')
		.isISO8601()
		.toDate()
		.withMessage('入库日期类型为时间类型'),
	skuId: body('sku_id').notEmpty().withMessage('sku_id不能为空').toInt(),
	numType: body('type').isIn(['0', '1', '']).withMessage('数量类型错误，0/1'),
	idcardType: query('type')
		.notEmpty()
		.withMessage('身份证审核结果不能为空')
		.isIn(['0', '1'])
		.withMessage('是否删除字段错误，0/1'),
	// 银行卡
	bankCardName: body('bank_name')
		.notEmpty()
		.withMessage('银行名不能为空')
		.isLength({ max: 20 })
		.withMessage('开银行名最长为20个字符'),
	bankCardType: body('bank_card_type')
		.toInt()
		.notEmpty()
		.withMessage('银行卡类型不能为空')
		.isIn([0, 1, 2, 3, 4])
		.withMessage('银行卡类型错误'),
	bankCardNum: query('card_num').isLength({ max: 20 }).withMessage('超出卡号限制20'),
	// 代办
	title: body('title')
		.notEmpty()
		.withMessage('标题不能为空')
		.isLength({ max: 100 })
		.withMessage('标题不能超过100个字符')
		.trim()
		.escape(),
	description: body('description').isLength({ max: 255 }).withMessage('待办描述不应该超过255个字符').trim().escape(),
	priority: body('priority').notEmpty().isIn(['yes', 'no']).withMessage('重要性只包含yes和no'),
	urgent: body('urgent').notEmpty().isIn(['yes', 'no']).withMessage('紧急性只包含yes和no')
};

/**
 * validate 高阶函数：根据验证器生成中间件
 *
 * @param {array} validators 验证器数组
 * @returns function Express的中间件
 */
const validate = (validators) => {
	return async (req, res, next) => {
		await Promise.all(validators.map((v) => v.run(req)));
		const errors = validationResult(req);
		if (errors.isEmpty()) {
			return next();
		}
		let err = {};
		for (let e of errors.array()) {
			if (e.param in err) err[e.param].push(e.msg);
			else err[e.param] = [e.msg];
		}
		res.json({ success: false, errors: err });
	};
};

module.exports = { validators, validate };
